package com.xbongbong.saas.analytical.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.domain.entity.PaasFormDataEntity;
import com.xbongbong.paas.elasticsearch.util.EsHelper;
import com.xbongbong.paas.enums.DelEnum;
import com.xbongbong.paas.enums.IndexTypeEnum;
import com.xbongbong.paas.field.FieldAttrEntity;
import com.xbongbong.paas.help.CommonHelp;
import com.xbongbong.paas.help.subform.TransferSubFormHelper;
import com.xbongbong.paas.pojo.dto.ValidateDataDTO;
import com.xbongbong.paas.redis.PaasRedisHelper;
import com.xbongbong.paas.redis.RedisPrefixConstant;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.DateTimeUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.pro.constant.AttrLenthConstant;
import com.xbongbong.pro.enums.ErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.OutstockErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.ProductErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.SettleAccountErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.pro.formdata.pojo.SaasNeedRedundantAttrPojo;
import com.xbongbong.saas.analytical.SaasValidateAnalyticalService;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.constant.ErrorMessageConstant;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.domain.entity.ProductWarehouseEntity;
import com.xbongbong.saas.domain.entity.SettleAccountsEntity;
import com.xbongbong.saas.domain.entity.ext.ProductEntityExt;
import com.xbongbong.saas.enums.SelectProductEnum;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.enums.business.InventoryEnum;
import com.xbongbong.saas.enums.business.ProductEnum;
import com.xbongbong.saas.enums.dictionary.InventoryNewStatusEnum;
import com.xbongbong.saas.enums.dictionary.InventoryStatusEnum;
import com.xbongbong.saas.enums.dictionary.InventoryTypeEnum;
import com.xbongbong.saas.enums.product.InventoryProductEnum;
import com.xbongbong.saas.enums.subform.ProductWarehouseSubFormEnum;
import com.xbongbong.saas.help.AnalyticalHelp;
import com.xbongbong.saas.help.SaasDataInitHelp;
import com.xbongbong.saas.help.SaveFormatHelp;
import com.xbongbong.saas.model.ProductModel;
import com.xbongbong.saas.model.SettleAccountsModel;
import com.xbongbong.saas.service.toolbox.help.UserTeamHelp;
import com.xbongbong.saas.toolbox.help.FastJsonHelper;
import com.xbongbong.util.ValidateUtil;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
import static org.elasticsearch.index.query.QueryBuilders.termsQuery;

/**
 * @author 吴峰
 * @date 2021/07/15 17:15
 */
@Service("inventoryAnalyticalServiceImpl")
public class InventoryValidateAnalyticalServiceImpl implements SaasValidateAnalyticalService {
    
    private static final Logger LOGGER = LoggerFactory.getLogger(InventoryValidateAnalyticalServiceImpl.class);
    
    @Resource
    private UserTeamHelp userTeamHelp;
    @Resource
    private CommonHelp commonHelp;
    @Resource
    private ProductModel productModel;
    @Resource
    private TransferSubFormHelper transferSubFormHelper;
    @Resource
    private EsHelper esHelper;
    @Resource
    private SettleAccountsModel settleAccountsModel;
    @Resource
    private PaasRedisHelper paasRedisHelper;
    @Resource
    private AnalyticalHelp analyticalHelp;

    @Override
    public List<Integer> type() {
        return Arrays.asList(XbbRefTypeEnum.INVENTORY.getCode());
    }

    @Override
    public void analyticalData(ValidateDataDTO validateDataDTO) throws XbbException {
        beforeSave(validateDataDTO);
        //没有负责团队的 单负责人
        userTeamHelp.checkPermissionOptionTeam(validateDataDTO);
    }
    
    public void beforeSave(ValidateDataDTO validateDataDTO) throws XbbException {
        try {
            JSONObject data = validateDataDTO.getData();
            String corpid = validateDataDTO.getCorpid();
            Long taskId = validateDataDTO.getTaskId();
            // 逻辑字段初始赋值
            SaasDataInitHelp.antDataSet(data, InventoryEnum.PRODUCT_CATEGORY.getAttr(), BasicConstant.ZERO);
            SaasDataInitHelp.antDataSet(data, InventoryEnum.IF_LOSS.getAttr(), BasicConstant.ZERO);
            SaasDataInitHelp.antDataSet(data, InventoryEnum.IF_PROFIT.getAttr(), BasicConstant.ZERO);
            SaasDataInitHelp.antDataSet(data, InventoryEnum.STATUS.getAttr(), InventoryStatusEnum.WAIT_OUT_INSTOCK.getCode());
            // 校验编号长度且编号存在
            Map<String, FieldAttrEntity> explainMap = validateDataDTO.getExplainMap();
            FieldAttrEntity fieldAttrEntity = new FieldAttrEntity();
            FieldAttrEntity sheetNo = explainMap.getOrDefault(InventoryEnum.SHEET_NO.getAttr(), fieldAttrEntity);
            FieldAttrEntity warehouse = explainMap.getOrDefault(InventoryEnum.WAREHOUSE_ID.getAttr(), fieldAttrEntity);
            FieldAttrEntity memoField = explainMap.getOrDefault(InventoryEnum.MEMO.getAttr(), fieldAttrEntity);
            FieldAttrEntity productField = explainMap.getOrDefault(InventoryEnum.PRODUCT.getAttr(), fieldAttrEntity);
            if (Objects.nonNull(sheetNo) && Objects.equals(sheetNo.getStrictController(), BasicConstant.ZERO)) {
                ValidateUtil.checkSerialNumber(validateDataDTO.getSerialNo(), Objects.toString(sheetNo.getAttrName(), ""));
            }
            //结账中校验
            Long date = data.getLong(InventoryEnum.TIME.getAttr());
            String redisHelperValue = paasRedisHelper.getValue(RedisPrefixConstant.SETTLE_ACCOUNTS, corpid);
            if (StringUtil.isNotEmpty(redisHelperValue)) {
                if (date <= DateTimeUtil.getTodayEndInt(Long.valueOf(redisHelperValue))) {
                    throw new XbbException(SettleAccountErrorCodeEnum.API_ERROR_254007);
                }
            }
            //结账内校验
            SettleAccountsEntity accountsEntity = settleAccountsModel.getLastSettleAccounts(corpid);
            if (Objects.nonNull(accountsEntity) && Objects.nonNull(accountsEntity.getCheckOutTime())) {
                if (date <= DateTimeUtil.getTodayEndInt(accountsEntity.getCheckOutTime())) {
                    throw new XbbException(OutstockErrorCodeEnum.API_ERROR_212051);
                }
            }
            // 校验仓库必须存在
            JSONArray warehouseJsonArray = FastJsonHelper.getJsonArrFromFormData(data, InventoryEnum.WAREHOUSE_ID.getAttr());
            if (warehouseJsonArray == null || warehouseJsonArray.isEmpty()) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100002.getCode(), ErrorMessageConstant.PLEASE_ENTER, Objects.toString(warehouse.getAttrName(), ""));
            }
            SaveFormatHelp.formatLinkBusiness4Save(data, InventoryEnum.WAREHOUSE_ID.getAttr(), InventoryEnum.WAREHOUSE_ID_LINKED_TEXT.getAttr(), InventoryEnum.WAREHOUSE_ID.getFieldType());
            // 校验备注长度
            ValidateUtil.checkFieldEntityLength(data, InventoryEnum.MEMO.getAttr(), Objects.toString(memoField.getAttrName(), ""), AttrLenthConstant.MEMO_MAX_LENGTH);

            //保存必填校验
            SaveFormatHelp.batchSaveRequiredCheck(validateDataDTO);
            JSONArray productArray = FastJsonHelper.getJsonArrOrDefaultFromFormData(data,InventoryEnum.PRODUCT.getAttr(),new JSONArray());
            if (productArray == null || productArray.isEmpty()) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100028.getCode(), ErrorMessageConstant.PLEASE_SELECT, Objects.toString(productField.getAttrName(), ""));
            }
            Long wareHouseId = FastJsonHelper.getLongOrDefaultFromFormData(data, InventoryEnum.WAREHOUSE_ID.getAttr(), 0L);
            // 快速盘点 校验产品是否开启序列号
            String type  = FastJsonHelper.getStringOrDefaultFromFormData(data, InventoryEnum.INVENTORY_TYPE.getAttr(), "0");
            if (Objects.equals(InventoryTypeEnum.FAST_INVENTORY.getCode(), type)) {
                List<Long> productIdList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                for (int i = 0; i < productArray.size(); i++) {
                    JSONObject productData = productArray.getJSONObject(i);
                    Long productId = productData.getLong(InventoryProductEnum.PRODUCT.getAttr());
                    productIdList.add(productId);
                }
                List<ProductEntityExt> productEntityExts = productModel.getProductListByIdIn(corpid, productIdList, DelEnum.NORMAL.getDel());
                for (ProductEntityExt productEntityExt : productEntityExts) {
                    JSONObject productData = productEntityExt.getData();
                    if (BasicConstant.ONE.equals(productData.getInteger(ProductEnum.ENABLE_SERIAL_NUMBER.getAttr()))) {
                        throw new XbbException(ProductErrorCodeEnum.API_ERROR_205082);
                    }
                }
            }
            boolean isNew = analyticalHelp.isNew(validateDataDTO.getDataId(), validateDataDTO.getTaskId(), corpid);
            Boolean productCanSee = true;
            if (!isNew) {
                productCanSee = commonHelp.attrCanSee(validateDataDTO.getExplainMap().get(InventoryEnum.PRODUCT.getAttr()),validateDataDTO.getDataId(),validateDataDTO.getCreatorId(),validateDataDTO.getLoginUser(),validateDataDTO.getCorpid(),XbbRefTypeEnum.INVENTORY.getCode());
            }
            //已经出库或入库，不允许编辑
            boolean hasInOrOut = (Objects.nonNull(data.getInteger(InventoryEnum.INSTOCK_ID.getAttr())) && !Objects.equals(data.getInteger(InventoryEnum.INSTOCK_ID.getAttr()),0))
                    || (Objects.nonNull(data.get(InventoryEnum.OUTSTOCK_ID.getAttr())) && !Objects.equals(data.getInteger(InventoryEnum.OUTSTOCK_ID.getAttr()),0));

            if (isNew || (productCanSee && !hasInOrOut)){
                data.put(InventoryEnum.INVENTORY_STATUS.getAttr(), InventoryNewStatusEnum.UNFINISHED.getCode());
                //如果未盘盈也为盘亏则是完成状态,在下面方法里重置了状态
                validateDataProduct(productArray,corpid,wareHouseId,data);
            }
            validateDataDTO.setData(data);
            Map<String,Boolean> attrCanSeeMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            attrCanSeeMap.put(InventoryEnum.PRODUCT.getAttr(),productCanSee);
            SaasNeedRedundantAttrPojo saasNeedRedundantAttrPojo = new SaasNeedRedundantAttrPojo();
            saasNeedRedundantAttrPojo.setAttrCanSeeMap(attrCanSeeMap);
            validateDataDTO.setSaasNeedRedundantAttrPoJo(saasNeedRedundantAttrPojo);
        } catch (XbbException e) {
            throw e;
        }catch (Exception e) {
            LOGGER.error("SupplierCommunicateValidateAnalyticalServiceImpl.beforeSave error", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
        }
    }

    private void validateDataProduct(JSONArray productArray, String corpid, Long warehouseId, JSONObject data) throws XbbException {
        Set<Long> pageProductIds = new HashSet<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long,Double> productNumMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        boolean ifProfit = false;
        boolean ifLoss = false;
        for (Object object:productArray) {
            JSONObject jsonObject = (JSONObject) object;
            Long productId = jsonObject.getLong(SelectProductEnum.PRODUCT.getAttr());
            pageProductIds.add(productId);
            Double productNum = jsonObject.getDouble(InventoryProductEnum.NUM.getAttr());
            Double oriNum = jsonObject.getDouble(InventoryProductEnum.STOCK.getAttr());
            if (productNum > oriNum){
                ifProfit = true;
            }else if (productNum < oriNum){
                ifLoss = true;
            }
            Double num = productNumMap.getOrDefault(productId,0D);
            num += productNum;
            productNumMap.put(productId,num);
        }
//        Map<Long,String> productNameMap = formDataValidateProductHelp.productExit(corpid,new ArrayList<>(pageProductIds));

        BoolQueryBuilder boolQueryBuilder = boolQuery();
        boolQueryBuilder.filter(termQuery("corpid.keyword",corpid));
        boolQueryBuilder.filter(termQuery(ProductWarehouseSubFormEnum.getEsAttr(ProductWarehouseSubFormEnum.WAREHOUSE_ID),warehouseId));
        boolQueryBuilder.filter(termsQuery(ProductWarehouseSubFormEnum.getEsAttr(ProductWarehouseSubFormEnum.PRODUCT_ID),pageProductIds));
        boolQueryBuilder.filter(termQuery(StringConstant.DEL,DelEnum.NORMAL.getDel()));
        boolQueryBuilder.filter(termQuery(ProductWarehouseSubFormEnum.getEsAttr(ProductWarehouseSubFormEnum.WAREHOUSE_CHECKED),1));
        List<PaasFormDataEntity> productWarehouseEntityList = esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_PRODUCT_WAREHOUSE,boolQueryBuilder, PaasFormDataEntity.class,null);
        List<ProductWarehouseEntity> productWarehouseEntities = transferSubFormHelper.transferFormDataToProductWarehouseList(productWarehouseEntityList);
        for (ProductWarehouseEntity entity : productWarehouseEntities){
            if (productNumMap.containsKey(entity.getProductId())){
                //TODO jxc盘点数量怎么校验
                productNumMap.remove(entity.getProductId());
            }
        }
        //TODO jxc 1期先这样，二期支持盘点库存不存在的产品
//        StringBuilder stringBuilder = new StringBuilder();
//        if (!productNumMap.isEmpty()){
//            for (Map.Entry<Long,Double> entry : productNumMap.entrySet()){
//                Long productId = entry.getKey();
//                String name = productNameMap.get(productId);
//                stringBuilder.append(name).append(",");
//            }
//            stringBuilder.insert(0,"产品:");
//            stringBuilder.append("不在仓库中");
//        }
//        if (!stringBuilder.toString().isEmpty()){
//            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100028.getCode(),stringBuilder.toString());
//        }
        data.put(InventoryEnum.IF_PROFIT.getAttr(),ifProfit ? 1 : 0);
        data.put(InventoryEnum.IF_LOSS.getAttr(),ifLoss ? 1 : 0);
        if (!ifProfit && !ifLoss) {
            data.put(InventoryEnum.INVENTORY_STATUS.getAttr(), InventoryNewStatusEnum.FINISHED.getCode());
        }
    }
}
